﻿interface Object {
    //普通对象的索引器
    [key: string]: any;
}

interface Date {
    /**
     * 获取日期属于周几
     */
    dayofWeek(): string;
    /**
     * 格式化日期字符串
     * @param {string} format 格式化字符串 同c#的格式
     *  默认格式是yyyy-MM-dd
     */
    format(format?: string): string;

    

    /**
     * 获取月头第一天日期
     */
    MonthFirst(): Date;
    /**
     * 获取约莫最后一天
     */
    MonthEnd(): Date;
    /**
     * 获取本周第一天(周一)
     */
    WeekFirst(): Date;
    /**
     * 获取本周最后一天(周日)
     */
    WeekEnd(): Date;

    /**
     * 增加n秒
     * @param sec
     */
    AddSeconds(seconds: number): Date;
    /**
     * 增加n分钟
     * @param {number} minutes
     */
    AddMinutes(minutes: number): Date;
    /**
     * 增加n个小时(可以为负数)
     * @param {number} hour
     */
    AddHours(hour: number): Date;
    /**
     * 增加n天
     * @param {number} days
     */
    AddDays(days: number): Date;
    /**
     * 增加n月
     * @param {number} month
     */
    AddMonths(month: number): Date;
    /**
     * 增加n年
     * @param {number} years
     */
    AddYears(years: number): Date;
}


module DateTime {


    Date.prototype.dayofWeek = function () {
        var week = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
        return week[this.getDay()];
    };

    Date.prototype.format = function (format: string) {
        var o: Object;
        o = {
            "M+": this.getMonth() + 1,
            "d+": this.getDate(),
            "h+": this.getHours(),
            "m+": this.getMinutes(),
            "s+": this.getSeconds(),
            "q+": Math.floor((this.getMonth() + 3) / 3),
            "S": this.getMilliseconds(),
            "ddd": this.dayofWeek()
        }
        if (!format) format = "yyyy-MM-dd";
        if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o) {
            if (o.hasOwnProperty(k)) {
                if (new RegExp(`(${k})`).test(format)) {
                    var tmp = RegExp.$1.length === 1 ? o[k] : (`00${o[k]}`).substr((`${o[k]}`).length);
                    format = format.replace(RegExp.$1, tmp);
                }
            }
        }
        return format;
    }

    Date.prototype.MonthFirst = function () {
        var result = new Date(this.getTime());
        result.setDate(1);
        return result;
    }

    Date.prototype.MonthEnd = function () {
        var result = new Date(this.getTime());
        result.setDate(DaysCount(this.getFullYear(), this.getMonth() + 1));
        return result;
    };

    Date.prototype.WeekFirst = function () {
        var day = this.getDay();
        if (day === 0) return this.AddDays(-6);
        else return new Date(this - (this.getDay() - 1) * 86400000);
    };

    Date.prototype.WeekEnd = function () {
        var weekFirstDay = this.WeekFirst();
        return new Date((weekFirstDay / 1000 + 6 * 86400) * 1000);
    };

    /**
     * 时间变化核心函数
     * @param {any[]} ...args
     * @returns
     */
    function AddDateTime(addType: string, numbers: number, dateTime: Date) {
        if (numbers == 0 || !addType) return dateTime;
        addType = addType.replace(/(^[\s　]*)|([\s　]*$)/g, "");
        addType = addType.toLowerCase();
        try {
            var giYear = dateTime.getFullYear();
            var giMonth = dateTime.getMonth();
            var giDay = dateTime.getDate();
            var giHour = dateTime.getHours();
            var giMinute = dateTime.getMinutes();
            var giSecond = dateTime.getSeconds();
            var giMillisecond = dateTime.getMilliseconds();
            switch (addType) {
                case "millisecond":
                    {
                        giMillisecond += numbers;
                        break;
                    }
                case "second":
                    {
                        giSecond += numbers;
                        break;
                    }
                case "minute":
                    {
                        giMinute += numbers;
                        break;
                    }
                case "hour":
                    {
                        giHour += numbers;
                        break;
                    }
                case "day":
                    {
                        giDay += numbers;
                        break;
                    }
                case "month":
                    {
                        giMonth += numbers;
                        break;
                    }
                case "year":
                    {
                        giYear += numbers;
                        break;
                    }
            }
            dateTime.setFullYear(giYear);
            dateTime.setMonth(giMonth);
            dateTime.setDate(giDay);
            dateTime.setHours(giHour);
            dateTime.setMinutes(giMinute);
            dateTime.setSeconds(giSecond);
            dateTime.setMilliseconds(giMillisecond);
        } catch (e) { }
        return dateTime;
    };


    Date.prototype.AddSeconds = function (seconds: number): Date {
        return AddDateTime("second", seconds, this);
    };

    Date.prototype.AddMinutes = function (minutes: number): Date {
        return AddDateTime("minute", minutes, this);
    };

    Date.prototype.AddHours = function (hours: number): Date {
        return AddDateTime("hour", hours, this);
    };

    Date.prototype.AddDays = function (days: number): Date {
        return AddDateTime("day", days, this);
    };

    Date.prototype.AddMonths = function (months: number): Date {
        return AddDateTime("month", months, this);
    };

    Date.prototype.AddYears = function (years: number): Date {
        return AddDateTime("year", years, this);
    }; 

    /**
     * 把字符串解析成日期时间格式
     * @param {string} str
     * @returns {Date} 时间
     */
    export function Parse(str: string): Date {
        if (!str) return null;
        var regexIso8601 = /^(?:-([0-9]{1,2})|([0-9]{4}))?(?:-?(?:([0-9]{2})?(?:-?([0-9]{2}))?|W([0-9]{2})(?:-?([1-7]))?|([0-9]{3})))?(?:T([0-9]{2})(?::?([0-9]{2})(?::?([0-9]{2}))?)?(?:[,\.]([0-9]+))?(?:(Z)|([+-])([0-9]{2})(?::?([0-9]{2}))?)?)?$/;
        var m: any = regexIso8601.exec(str);
        if (m) {
            return new Date(
                m[2],
                (m[3] || 1) - 1,
                m[4] || 1,
                m[8] || 0,
                m[9] || 0,
                m[10] || 0,
                m[11] || 0
            );
        }
    };

    /**
     * 判断指定年是否为闰年
     * @param {number} year
     * @returns 
     */
    export function IsLeapYear(year: number): Boolean {
        return (year % 4 === 0) || (year % 100 === 0) || (year % 400 === 0);
    }

    /**
     * 获取某年或某月的总天数
     * @param {number} year 年份
     * @param {number} month? 月份
     * @return {number} 天数
     */
    export function DaysCount(year: number, month?: number): number {
        var months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        if (!month) return IsLeapYear(year) ? 366 : 365;
        var days = months[month - 1];
        if (IsLeapYear(year) && month == 2) days = 29;
        return days;
    }

    /**
     * 返回某年每个月的天数
     * @param {number} year
     */
    export function MonthDaysList(year: number): Array<Number> {
        var months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        if (IsLeapYear(year)) months[1] = 29;
        return months;
    }

    /**
     * 获取一个日期所在月的天数
     * @param date
     */
    export function MonthDays(date: Date): number {
        
        return DaysCount(date.getFullYear(),date.getMonth()+1);
    }
}

